feat(FR-2840): migrate to pnpm v11#7307
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has required the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
6483b89 to
0ff9a30
Compare
There was a problem hiding this comment.
Pull request overview
Upgrades the monorepo’s package manager/runtime from pnpm v10 to pnpm v11, moving pnpm-specific configuration to v11-supported locations, updating CI/workflows to use pnpm 11, and regenerating the lockfile under pnpm 11 (with a CI-scoped minimumReleaseAge override to avoid upstream metadata issues).
Changes:
- Bump root
package.jsontoengines.pnpm: ^11.0.0, addpackageManager: pnpm@11.0.8, and migratepnpm.overridesout ofpackage.json. - Update
pnpm-workspace.yamlfor pnpm v11 (onlyBuiltDependencies→allowBuilds, moveoverrides, remove staleminimumReleaseAgeExclude). - Pin workflows/composite actions/agentic workflows to pnpm 11 +
pnpm/action-setup@v5, and add--config.minimum-release-age=0to CIpnpm installinvocations; regeneratepnpm-lock.yaml.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
pnpm-workspace.yaml |
Migrates pnpm workspace config to v11 semantics (allowBuilds, overrides), removes stale exclude list. |
package.json |
Bumps pnpm engine requirement, adds packageManager, removes pnpm config block. |
pnpm-lock.yaml |
Regenerated lockfile under pnpm 11.0.8. |
.npmrc |
Removes engine-strict=true, leaves a comment clarifying scope. |
.github/workflows/vitest.yml |
Pins pnpm to v11, upgrades pnpm/action-setup to v5, adds CI install override flag. |
.github/workflows/package.yml |
Pins pnpm to v11 and adds --config.minimum-release-age=0 to installs across jobs. |
.github/workflows/publish-backend.ai-ui.yml |
Pins pnpm to v11 and adds CI install override flag. |
.github/workflows/publish-backend.ai-docs-toolkit.yml |
Pins pnpm to v11 and adds CI install override flag. |
.github/workflows/weekly-merge-branch-lockfiles.yml |
Pins pnpm to v11 and adds CI install override flag to merge step. |
.github/actions/daily-test-improver/coverage-steps/action.yml |
Pins pnpm to v11 and adds CI install override flag in composite action. |
.github/workflows/e2e-watchdog.md |
Updates agentic workflow to pnpm/action-setup@v5, pnpm v11, and CI install override flag. |
.github/workflows/e2e-watchdog.lock.yml |
Updates compiled workflow to v5 SHA, pnpm v11, and CI install override flag. |
.github/workflows/e2e-healer.md |
Updates agentic workflow to pnpm/action-setup@v5, pnpm v11, and CI install override flag. |
.github/workflows/e2e-healer.lock.yml |
Updates compiled workflow to v5 SHA, pnpm v11, and CI install override flag. |
.github/aw/actions-lock.json |
Updates action lock entry from pnpm/action-setup@v4 → @v5 SHA. |
.specs/FR-2840-pnpm-v11-migration/spec.md |
Adds migration spec + acceptance checklist for review/verification. |
.specs/FR-2840-pnpm-v11-migration/dev-plan.md |
Adds dev-plan for executing the migration steps. |
6afc4b2 to
303974c
Compare
303974c to
a420c70
Compare
Merge activity
|
Resolves #7296(FR-2840) ## Summary Upgrade the repo from pnpm v10 to pnpm v11 in a single PR. Predecessor PR #7297 (FR-2839) temporarily pinned CI workflows to pnpm v10 to unblock CI; this PR completes the migration so we don't get stuck on v10. ## Key decisions and rationale The migration ran into several pnpm 11 behavior changes and upstream bugs that required explicit decisions. These were discussed and chosen during implementation; this section is the lasting record so the decisions don't have to be re-derived in review. ### 1. Single PR for the whole migration **Decision**: deliver as one PR (config moves + workflow updates + lockfile regen). **Rationale**: lockfile regen, config moves (`pnpm.overrides` → `pnpm-workspace.yaml`), `onlyBuiltDependencies` → `allowBuilds` conversion, and the workflow `version: 11` bump must land **atomically** — splitting forces an intermediate commit where either CI is on v10 with v11 config (breaks) or on v11 with v10 config (breaks). The dev plan documents this reasoning at `.specs/FR-2840-pnpm-v11-migration/dev-plan.md`. ### 2. Drop `package.json` `pnpm` field; absorb `overrides` into `pnpm-workspace.yaml` **Decision**: move the three `overrides` (`tar-fs@2`, `node-forge`, `@codemirror/state`) into `pnpm-workspace.yaml` and delete the top-level `pnpm` block from `package.json`. **Rationale**: pnpm 11 no longer reads the `pnpm` field in `package.json`. Leaving it would silently lose those overrides at install time. ### 3. `onlyBuiltDependencies` (list) → `allowBuilds` (map) **Decision**: 1:1 conversion — same 9 packages (`bufferutil`, `core-js`, `core-js-pure`, `electron`, `es5-ext`, `esbuild`, `sharp`, `unrs-resolver`, `utf-8-validate`). **Rationale**: `onlyBuiltDependencies` was removed in pnpm 11; `allowBuilds` is its replacement. ### 4. Drop `minimumReleaseAgeExclude` block entirely **Decision**: remove the seven entries (`react@19.2.4`, `i18next@25.7.4`, `antd@6.1.3`, …). **Rationale**: those entries pinned exact versions that the catalog has long since moved past. Under pnpm 11 the entries no longer match anything in the resolved tree, so they're dead config. ### 5. Drop `engine-strict=true` from `.npmrc` **Decision**: remove the line; replace `.npmrc` with a one-line comment about scope. **Rationale**: pnpm 11 enforces `engines.pnpm` natively when set, and v11 narrows `.npmrc` to auth/registry settings only. ### 6. Bump `pnpm/action-setup` references to `@v5` everywhere (also fixes `vitest.yml@v4`) **Decision**: every `pnpm/action-setup` reference uses `@v5` or the matching v5 SHA; `.github/aw/actions-lock.json` is updated to the v5 SHA (`a8198c4bff370c8506180b035930dea56dbd5288`). **Rationale**: `vitest.yml:146` was on `@v4` while siblings were `@v5` — flagged as cleanup during PR #7297 review. While in the area, also bumped agentic `e2e-watchdog.md`/`e2e-healer.md` and the SHA-pinned `.lock.yml` siblings so the next gh-aw regen doesn't re-introduce v4. ### 7. CI: every install lane uses `--frozen-lockfile`; `--config.minimum-release-age=0` only on the weekly-merge job **Decision**: see the table below. Every CI `pnpm install` runs `--frozen-lockfile`. The single intrinsic exception is `weekly-merge-branch-lockfiles.yml`, whose purpose **is** to re-resolve and merge per-branch lockfiles. | Workflow | Mode | Override needed? | |---|---|---| | `vitest.yml` (3 jobs) | `--frozen-lockfile` (was `--merge-git-branch-lockfiles --no-frozen-lockfile`) | ❌ No | | `package.yml` (5 lines) | `--frozen-lockfile` (was `--no-frozen-lockfile`) | ❌ No | | `daily-test-improver/coverage-steps/action.yml` | `--frozen-lockfile` (was `--no-frozen-lockfile`) | ❌ No | | `publish-backend.ai-{ui,docs-toolkit}.yml` | `--frozen-lockfile` | ❌ No | | `e2e-{watchdog,healer}.{md,lock.yml}` | `--frozen-lockfile --prefer-offline` | ❌ No | | `weekly-merge-branch-lockfiles.yml` | `--merge-git-branch-lockfiles --no-frozen-lockfile --config.minimum-release-age=0` | ✅ Yes (intrinsic) | **Rationale**: pnpm 11's stricter `minimumReleaseAge` enforcement breaks `pnpm install` against this dep tree in two ways the upstream does not yet fix: 1. **`ERR_PNPM_MISSING_TIME` (cache/metadata bug)** — pnpm 11 fatals on packages whose npm registry abbreviated metadata is missing the `time` field, even though the full metadata file has it. Tracked in [pnpm/pnpm#9963](pnpm/pnpm#9963) (closed but recurring) and [pnpm/pnpm#9968](pnpm/pnpm#9968) (10.16.1 fix is partial). Maintainer comment on #9963: *"the error should not happen at all. The full metadata and the abbreviated one are stored at different locations."* The recommended `pnpm store prune` workaround did not produce stable results — re-tested after each iteration and the error reappeared on different packages. 2. **Optional/platform binaries fataling** — `vitest`/`rollup`'s `optionalDependencies` declares 15+ `@rollup/rollup-*` platform binaries. Pnpm 11 fatals on each one's missing `time` metadata. Same shape as [pnpm/pnpm#10699 (open)](pnpm/pnpm#10699). These bugs only fire during **resolution**. Once the lockfile is generated, `--frozen-lockfile` installs from it without re-resolving and never touches the time check — so 99% of CI lanes don't need any workaround at all. Only `weekly-merge-branch-lockfiles.yml` has to re-resolve (its purpose is to merge per-branch lockfiles into the canonical), so it's the only place that carries the override. This decision was the result of three rounds of refinement: started with override on every install, narrowed to "only re-resolve lanes" after empirical scoping, then narrowed again to "only the one re-resolve lane that exists" by switching the rest to `--frozen-lockfile`. The earlier exclude-list approach (add offending packages to `minimumReleaseAgeExclude`) was attempted and abandoned — empirical iteration grew the list past 30 entries without converging because every new rollup architecture binary, every metadata corruption, and every recent typescript-eslint family bump re-broke it. ### 8. Trade-off accepted with `--frozen-lockfile` **Decision**: PRs that change deps must run `pnpm install` locally and commit the updated lockfile (or branch lockfile) before pushing. CI no longer auto-resolves on those PRs. **Rationale**: stricter contract, but more honest. CI's role is to verify, not to silently mutate the lockfile. Local devs that hit MISSING_TIME / NO_MATURE during their manual install can use `pnpm install --config.minimum-release-age=0` as a one-off until upstream pnpm fixes #9963 / #10699. ### 9. Keep `minimumReleaseAge: 10080` in `pnpm-workspace.yaml` **Decision**: don't lower the policy value to 0 or 1440 just because pnpm 11 makes it painful. **Rationale**: the 7-day supply-chain protection is a deliberate project policy. The pnpm 11 enforcement bugs are temporary upstream issues; the policy outlives them. Workflow-level override scopes the relaxation to the one place that genuinely needs it (the merge job, which a human reviews before merging the resulting PR). ### 10. Out of scope (deliberate) - Per-branch `pnpm-lock.<branch>.yaml` files for other developers' branches are intentionally **not** consolidated in this PR. The `weekly-merge-branch-lockfiles` workflow already handles that on its own cadence. - Pre-existing TypeScript errors (`packages/backend.ai-client/src/client.ts` implicit-`any`s, `DeleteForeverVFolderModalV2.tsx` `BulkPurgeVFoldersV2Input.options`) — verified to exist on `main`, not introduced by this migration. - Re-evaluating the long-term `minimumReleaseAge` policy. Spec §5.4.1 documents the single CI exception; a strategic decision can come in a follow-up once pnpm fixes the upstream bugs. ## Test plan - [x] `pnpm install --frozen-lockfile` succeeds locally under pnpm 11.0.8 against the regenerated lockfile (~10s, no MISSING_TIME / NO_MATURE errors). - [x] `bash scripts/verify.sh` — Relay/Lint/Format pass; TypeScript failures are confirmed pre-existing on `main` (verified by checking out `main` and re-running). Out of scope for this PR. - [ ] CI on this PR — `Analyze`/`CodeQL`/`triage`/`mergeability_check`/`auto-label`/`sync-project-status` pass. - [ ] After merge, re-run failed CI on a recent PR (e.g. on top of this) and confirm `pnpm -v` reports 11.x and the install step passes. ## Spec Full migration spec is committed in this PR at `.specs/FR-2840-pnpm-v11-migration/spec.md` with the §8 acceptance checklist for the reviewer to tick.
fdfe95b to
3c023bb
Compare
a420c70 to
4968a7f
Compare
…ield) (#7345) Resolves #7344(FR-2861) ## Summary Since the pnpm v11 migration ([FR-2840 / #7307](#7307)), the root `package.json` declares `"packageManager": "pnpm@11.1.0"`. Several GitHub Actions workflows still pass `version: 11` to `pnpm/action-setup@v5`, which fails on every PR with: ``` Error: Multiple versions of pnpm specified: - version 11 in the GitHub Action config with the key "version" - version pnpm@11.1.0 in the package.json with the key "packageManager" Remove one of these versions to avoid version mismatch errors like ERR_PNPM_BAD_PM_VERSION ``` Example failure: https://github.com/lablup/backend.ai-webui/actions/runs/25669252851/job/75349895261 This blocks `react-vitest` (and the publish / package / weekly-merge / e2e-watchdog / e2e-healer jobs) for every open PR. ## Fix Drop the `version: 11` input from all `pnpm/action-setup@v5` calls. With `packageManager` set, pnpm/action-setup uses it as the single source of truth. For two `.lock.yml` steps where `version: 11` was the only `with:` input, also drop the now-empty `with:` mapping (which GitHub Actions rejects). Also bump the pinned pnpm version from `11.0.8` to `11.1.0` (current npm `latest`) so the field reflects the latest patch. Verified via `corepack prepare pnpm@11.1.0 --activate` + `pnpm install --frozen-lockfile` (lockfile compatible — no migration). ## Changes - `.github/workflows/vitest.yml` (3 occurrences — the active PR blocker) - `.github/workflows/publish-backend.ai-ui.yml` - `.github/workflows/publish-backend.ai-docs-toolkit.yml` - `.github/workflows/package.yml` (4) - `.github/workflows/weekly-merge-branch-lockfiles.yml` - `.github/workflows/e2e-healer.lock.yml` (also drop empty `with:`) - `.github/workflows/e2e-watchdog.lock.yml` (also drop empty `with:`) - `.github/actions/daily-test-improver/coverage-steps/action.yml` (composite action, surfaced by Copilot) - `package.json` — bump `packageManager` to `pnpm@11.1.0` - `amplify.yml` — sync the pinned-version comment `e2e-watchdog.md` / `e2e-healer.md` are documentation, not active workflows — left untouched. ## Verification - The pnpm/action-setup error will not reproduce against this PR's CI. - Existing tests run as before (no change to install command, just the action input). - `pnpm install --frozen-lockfile` with `pnpm@11.1.0` reports `Already up to date` — lockfile remains valid.

Resolves #7296(FR-2840)
Summary
Upgrade the repo from pnpm v10 to pnpm v11 in a single PR. Predecessor PR #7297 (FR-2839) temporarily pinned CI workflows to pnpm v10 to unblock CI; this PR completes the migration so we don't get stuck on v10.
Key decisions and rationale
The migration ran into several pnpm 11 behavior changes and upstream bugs that required explicit decisions. These were discussed and chosen during implementation; this section is the lasting record so the decisions don't have to be re-derived in review.
1. Single PR for the whole migration
Decision: deliver as one PR (config moves + workflow updates + lockfile regen).
Rationale: lockfile regen, config moves (
pnpm.overrides→pnpm-workspace.yaml),onlyBuiltDependencies→allowBuildsconversion, and the workflowversion: 11bump must land atomically — splitting forces an intermediate commit where either CI is on v10 with v11 config (breaks) or on v11 with v10 config (breaks). The dev plan documents this reasoning at.specs/FR-2840-pnpm-v11-migration/dev-plan.md.2. Drop
package.jsonpnpmfield; absorboverridesintopnpm-workspace.yamlDecision: move the three
overrides(tar-fs@2,node-forge,@codemirror/state) intopnpm-workspace.yamland delete the top-levelpnpmblock frompackage.json.Rationale: pnpm 11 no longer reads the
pnpmfield inpackage.json. Leaving it would silently lose those overrides at install time.3.
onlyBuiltDependencies(list) →allowBuilds(map)Decision: 1:1 conversion — same 9 packages (
bufferutil,core-js,core-js-pure,electron,es5-ext,esbuild,sharp,unrs-resolver,utf-8-validate).Rationale:
onlyBuiltDependencieswas removed in pnpm 11;allowBuildsis its replacement.4. Drop
minimumReleaseAgeExcludeblock entirelyDecision: remove the seven entries (
react@19.2.4,i18next@25.7.4,antd@6.1.3, …).Rationale: those entries pinned exact versions that the catalog has long since moved past. Under pnpm 11 the entries no longer match anything in the resolved tree, so they're dead config.
5. Drop
engine-strict=truefrom.npmrcDecision: remove the line; replace
.npmrcwith a one-line comment about scope.Rationale: pnpm 11 enforces
engines.pnpmnatively when set, and v11 narrows.npmrcto auth/registry settings only.6. Bump
pnpm/action-setupreferences to@v5everywhere (also fixesvitest.yml@v4)Decision: every
pnpm/action-setupreference uses@v5or the matching v5 SHA;.github/aw/actions-lock.jsonis updated to the v5 SHA (a8198c4bff370c8506180b035930dea56dbd5288).Rationale:
vitest.yml:146was on@v4while siblings were@v5— flagged as cleanup during PR #7297 review. While in the area, also bumped agentice2e-watchdog.md/e2e-healer.mdand the SHA-pinned.lock.ymlsiblings so the next gh-aw regen doesn't re-introduce v4.7. CI: every install lane uses
--frozen-lockfile;--config.minimum-release-age=0only on the weekly-merge jobDecision: see the table below. Every CI
pnpm installruns--frozen-lockfile. The single intrinsic exception isweekly-merge-branch-lockfiles.yml, whose purpose is to re-resolve and merge per-branch lockfiles.vitest.yml(3 jobs)--frozen-lockfile(was--merge-git-branch-lockfiles --no-frozen-lockfile)package.yml(5 lines)--frozen-lockfile(was--no-frozen-lockfile)daily-test-improver/coverage-steps/action.yml--frozen-lockfile(was--no-frozen-lockfile)publish-backend.ai-{ui,docs-toolkit}.yml--frozen-lockfilee2e-{watchdog,healer}.{md,lock.yml}--frozen-lockfile --prefer-offlineweekly-merge-branch-lockfiles.yml--merge-git-branch-lockfiles --no-frozen-lockfile --config.minimum-release-age=0Rationale: pnpm 11's stricter
minimumReleaseAgeenforcement breakspnpm installagainst this dep tree in two ways the upstream does not yet fix:ERR_PNPM_MISSING_TIME(cache/metadata bug) — pnpm 11 fatals on packages whose npm registry abbreviated metadata is missing thetimefield, even though the full metadata file has it. Tracked in pnpm/pnpm#9963 (closed but recurring) and pnpm/pnpm#9968 (10.16.1 fix is partial). Maintainer comment on #9963: "the error should not happen at all. The full metadata and the abbreviated one are stored at different locations." The recommendedpnpm store pruneworkaround did not produce stable results — re-tested after each iteration and the error reappeared on different packages.vitest/rollup'soptionalDependenciesdeclares 15+@rollup/rollup-*platform binaries. Pnpm 11 fatals on each one's missingtimemetadata. Same shape as pnpm/pnpm#10699 (open).These bugs only fire during resolution. Once the lockfile is generated,
--frozen-lockfileinstalls from it without re-resolving and never touches the time check — so 99% of CI lanes don't need any workaround at all. Onlyweekly-merge-branch-lockfiles.ymlhas to re-resolve (its purpose is to merge per-branch lockfiles into the canonical), so it's the only place that carries the override.This decision was the result of three rounds of refinement: started with override on every install, narrowed to "only re-resolve lanes" after empirical scoping, then narrowed again to "only the one re-resolve lane that exists" by switching the rest to
--frozen-lockfile. The earlier exclude-list approach (add offending packages tominimumReleaseAgeExclude) was attempted and abandoned — empirical iteration grew the list past 30 entries without converging because every new rollup architecture binary, every metadata corruption, and every recent typescript-eslint family bump re-broke it.8. Trade-off accepted with
--frozen-lockfileDecision: PRs that change deps must run
pnpm installlocally and commit the updated lockfile (or branch lockfile) before pushing. CI no longer auto-resolves on those PRs.Rationale: stricter contract, but more honest. CI's role is to verify, not to silently mutate the lockfile. Local devs that hit MISSING_TIME / NO_MATURE during their manual install can use
pnpm install --config.minimum-release-age=0as a one-off until upstream pnpm fixes #9963 / #10699.9. Keep
minimumReleaseAge: 10080inpnpm-workspace.yamlDecision: don't lower the policy value to 0 or 1440 just because pnpm 11 makes it painful.
Rationale: the 7-day supply-chain protection is a deliberate project policy. The pnpm 11 enforcement bugs are temporary upstream issues; the policy outlives them. Workflow-level override scopes the relaxation to the one place that genuinely needs it (the merge job, which a human reviews before merging the resulting PR).
10. Out of scope (deliberate)
pnpm-lock.<branch>.yamlfiles for other developers' branches are intentionally not consolidated in this PR. Theweekly-merge-branch-lockfilesworkflow already handles that on its own cadence.packages/backend.ai-client/src/client.tsimplicit-anys,DeleteForeverVFolderModalV2.tsxBulkPurgeVFoldersV2Input.options) — verified to exist onmain, not introduced by this migration.minimumReleaseAgepolicy. Spec §5.4.1 documents the single CI exception; a strategic decision can come in a follow-up once pnpm fixes the upstream bugs.Test plan
pnpm install --frozen-lockfilesucceeds locally under pnpm 11.0.8 against the regenerated lockfile (~10s, no MISSING_TIME / NO_MATURE errors).bash scripts/verify.sh— Relay/Lint/Format pass; TypeScript failures are confirmed pre-existing onmain(verified by checking outmainand re-running). Out of scope for this PR.Analyze/CodeQL/triage/mergeability_check/auto-label/sync-project-statuspass.pnpm -vreports 11.x and the install step passes.Spec
Full migration spec is committed in this PR at
.specs/FR-2840-pnpm-v11-migration/spec.mdwith the §8 acceptance checklist for the reviewer to tick.